package cn.dakaqi.services.impl;

import cn.dakaqi.dao.ActivityDao;
import cn.dakaqi.dao.ActivitySignRecordDao;
import cn.dakaqi.entities.Activity;
import cn.dakaqi.entities.ActivitySign;
import cn.dakaqi.entities.ActivitySignRecord;
import cn.dakaqi.entities.PlatformGroup;
import cn.dakaqi.enumerate.CommonStatusCode;
import cn.dakaqi.services.ActivitySignRecordService;
import cn.dakaqi.services.ActivitySignService;
import cn.dakaqi.services.PlatformGroup2Service;
import cn.dakaqi.services.user.VolunteerService;
import cn.dakaqi.utils.Clock;
import cn.dakaqi.utils.DKQConstant;
import cn.dakaqi.utils.DateUtil;
import cn.dakaqi.utils.exception.ServiceRuntimeException;
import cn.dakaqi.utils.latitude.LatitudeUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author chunyang on 2016/4/17.
 */
@Component(value = "activitySignRecordService")
@Transactional
public class ActivitySignRecordServiceImpl implements ActivitySignRecordService
{
    @Autowired
    ActivityDao activityDao;
    @Autowired
    ActivitySignRecordDao activitySignRecordDao;
    @Autowired
    ActivitySignService activitySignService;
    @Autowired
    VolunteerService volunteerService;
    @Autowired
    PlatformGroup2Service platformGroupService;

    @Override
    public ActivitySign save(String param) throws ServiceRuntimeException
    {
        JSONObject jsonObject = JSON.parseObject(param);
        String memberCode = jsonObject.getString("memberCode");
        String activityCode = jsonObject.getString("activityCode");
        double lng = jsonObject.getDouble("lng");
        double lat = jsonObject.getDouble("lat");

        Activity activity = this.activityDao.findByActivityCode(activityCode);
        ActivitySignRecord activitySignRecord = new ActivitySignRecord();
        activitySignRecord.setVolunteer(volunteerService.findByMemberCode(memberCode));
        activitySignRecord.setActivity(activity);
        activitySignRecord.setCreateTime(Clock.DEFAULT.getCurrentDate());
        activitySignRecord.setLng(lng);
        activitySignRecord.setLat(lat);
        Map<String, String> address = LatitudeUtils.getGeocoderAddress(lat, lng);
        if (null != address)
            activitySignRecord.setAdress(address.get("address"));
        return this.save(activitySignRecord);
    }

    @Override
    public ActivitySign save(String memberCode, String activityCode, double lng, double lat)
    {
        Activity activity = this.activityDao.findByActivityCode(activityCode);
        ActivitySignRecord activitySignRecord = new ActivitySignRecord();
        activitySignRecord.setVolunteer(volunteerService.findByMemberCode(memberCode));
        activitySignRecord.setActivity(activity);
        activitySignRecord.setCreateTime(Clock.DEFAULT.getCurrentDate());
        activitySignRecord.setLng(lng);
        activitySignRecord.setLat(lat);
        Map<String, String> address = LatitudeUtils.getGeocoderAddress(lat, lng);
        if (null != address)
            activitySignRecord.setAdress(address.get("address"));
        return this.save(activitySignRecord);
    }

    @Override
    public ActivitySign save(ActivitySignRecord activitySignRecord) throws ServiceRuntimeException
    {
        //检查活动是否已被封存
        if (activitySignRecord.getActivity().getLocked() == DKQConstant.ACTIVITY_LOCK ||
                activitySignRecord.getActivity().getActStatus() == DKQConstant.ACT_STATUS_LOCKED)
        {
            throw new ServiceRuntimeException(CommonStatusCode.ACTIVITY_IS_CLOSE.getStatusCode(),
                    CommonStatusCode.ACTIVITY_IS_CLOSE.getStatusMessage() + ",不可以打卡");
        }

        //检查活动的签到处是否在指定的范围内
        if (!checkDistance(activitySignRecord))
        {
            throw new ServiceRuntimeException(CommonStatusCode.SIGN_NOT_NEARBY.getStatusCode(),
                    CommonStatusCode.SIGN_NOT_NEARBY.getStatusMessage());
        }

        //活动开始前2小时或结束后2小时内都是有效签到
        int minutes = DateUtil.countMinutes2(DateUtil.date2Str(new Date(), DateUtil.DATETIME_YYYY_MM_DD_HH_MM_SS),
                activitySignRecord.getActivity().getStartTime() + ":00");
        if (minutes > 120)
        {
            throw new ServiceRuntimeException(CommonStatusCode.SIGN_NO_TIME_TO.getStatusCode(),
                    CommonStatusCode.SIGN_NO_TIME_TO.getStatusMessage());
        }

        //活动未开始时，查询当前用户当前活动累计签到次数，不可以进行签退
        if (activitySignRecord.getActivity().getActStatus() < DKQConstant.ACT_STATUS_PROCESS)
        {
            List<ActivitySignRecord> list0 = this.queryByMemberAndActivity(activitySignRecord.getVolunteer().getMemberCode(),
                    activitySignRecord.getActivity().getActivityCode(), 1);
            if (null != list0 && list0.size() >= 1)
            {
                throw new ServiceRuntimeException(CommonStatusCode.ACTIVITY_NOT_START.getStatusCode(),
                        "活动未开始,不可以签出!");
            }
        }

        //若活动已结束，则判断用户是否是第一次签入，
        if(activitySignRecord.getActivity().getActStatus() == DKQConstant.ACT_STATUS_END)
        {
            List<ActivitySignRecord> list0 = this.queryByMemberAndActivity(activitySignRecord.getVolunteer().getMemberCode(),
                    activitySignRecord.getActivity().getActivityCode(), 1);
            if (null == list0 || list0.size() == 0)
            {
                throw new ServiceRuntimeException(CommonStatusCode.ACTIVITY_NOT_START.getStatusCode(),
                        "活动已结束,不可以签到!");
            }
        }
        //保存签到记录
        this.activitySignRecordDao.save(activitySignRecord);
        //检查当前用户当前活动的所有打卡记录
        List<ActivitySignRecord> list = this.queryByMemberAndActivity(activitySignRecord.getVolunteer().getId(),
                activitySignRecord.getActivity().getId(), 1);
        if (null == list)
        {
            return null;
        }

        //若有2次以上的签到记录，则记录公益时间
        ActivitySign activitySign = new ActivitySign();
        //检查当前用户是否已在本次活动的公益记录
        ActivitySign data = activitySignService.queryByMemberAndActivity(activitySignRecord.getVolunteer().getId(),
                activitySignRecord.getActivity().getId());

        if (null != data && list.size() >= 2)
        {
            int times;
            int oldTime = data.getTimes();
            int targetTimes;//本次活动实际时长
            //计算两次签到时间的差
            String firstRecord = this.findFirstRecord(activitySignRecord.getVolunteer().getId(), activitySignRecord.getActivity().getId());
            String lastRecord = this.findLastRecord(activitySignRecord.getVolunteer().getId(), activitySignRecord.getActivity().getId());

            String startTime = activitySignRecord.getActivity().getStartTime();
            String endTime = activitySignRecord.getActivity().getEndTime();
            targetTimes = DateUtil.countMinutes(startTime, endTime);
            //若第一次签到时间在活动开始之前则是：最后一次签到时间-活动的开始时间；若第一次签到时间在活动开始之后，则是最后一次签到时间-第一次签到时间
            Date firstSign = DateUtil.str2Date(firstRecord, DateUtil.DATETIME_YYYY_MM_DD_HH_MM);
            Date actStartDate = DateUtil.str2Date(activitySignRecord.getActivity().getStartTime(),
                    DateUtil.DATETIME_YYYY_MM_DD_HH_MM);

            if (firstSign.before(actStartDate))
            {
                times = DateUtil.countMinutes(activitySignRecord.getActivity().getStartTime(), lastRecord);
                if (times >= targetTimes)
                {
                    times = targetTimes;
                }
                System.out.println("第一次签到时间在活动开始之------前：" + times);
            } else
            {
                times = DateUtil.countMinutes(firstRecord, lastRecord);
                if (times >= targetTimes)
                {
                    times = targetTimes;
                }
                System.out.println("第一次签到时间在活动开始之------后：" + times);
            }

            if (times > 0 && data.getActivity().getActStatus() >= DKQConstant.ACT_STATUS_PROCESS)
            {
                System.out.println("本次是一次有效签出");
                data.setTimes(times);
                activitySign = activitySignService.updateTimes(data, oldTime);
            }
            return activitySign;
        }
        else
        {
            List<PlatformGroup> platformGroups = this.platformGroupService.findByGroup(activitySignRecord.getActivity().getGroup().getId());
            //查询当前社团挂靠了哪些组织
            String orgs = "";
            if (null != platformGroups && platformGroups.size() > 0)
            {
                for (PlatformGroup p : platformGroups)
                {
                    orgs = orgs + "{" + p.getParentCode() + "},";
                }
            }
            activitySign = ActivitySign.build(activitySignRecord, 0, orgs);
            activitySignService.save(activitySign);
            return activitySign;
        }
    }


    @Override
    public void saveMaibao(ActivitySignRecord firstSignRecord, ActivitySignRecord lastSignRecord) throws ServiceRuntimeException
    {
        //保存签到记录
        this.activitySignRecordDao.save(firstSignRecord);
        this.activitySignRecordDao.save(lastSignRecord);
        ActivitySign activitySign = new ActivitySign();
        activitySign.setVolunteer(firstSignRecord.getVolunteer());
        activitySign.setActivity(firstSignRecord.getActivity());
        activitySign.setCreateTime(Clock.DEFAULT.getCurrentDate());
        activitySign.setTimes(DateUtil.countMinutes(firstSignRecord.getActivity().getStartTime(), firstSignRecord.getActivity().getEndTime()));
        activitySign.setDelStatus(DKQConstant.DEL_NO);
        activitySign.setStatus(0);
        activitySign.setLat(firstSignRecord.getLat());
        activitySign.setLng(firstSignRecord.getLng());
        activitySignService.save(activitySign);
    }

    public static void main(String[] args)
    {
        try
        {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date firstSign = sdf.parse("2016-08-16 09:53:09");
            Date actStartDate = sdf.parse("2016-08-16 09:55");
            if (firstSign.before(actStartDate))
            {
                System.out.println("is before");
                int times = DateUtil.countMinutes("2016-08-16 09:55", "2016-08-16 10:00:10");
                System.out.println(times);
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 检查是不是在有效的范围内打卡
     *
     * @param activitySignRecord 打卡请求
     * @return boolean
     */
    private boolean checkDistance(ActivitySignRecord activitySignRecord)
    {
        if (activitySignRecord.getActivity().getScope() < 0)
        {
            return true;
        }

        //计算两点间的距离
        double distance = LatitudeUtils.GetDistance(activitySignRecord.getLng(), activitySignRecord.getLat(), activitySignRecord.getActivity().getLng(), activitySignRecord.getActivity().getLat());
        return distance <= activitySignRecord.getActivity().getScope();
    }

    @Override
    public Page<ActivitySignRecord> queryByMember(String memberCode, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String, Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.memberCode", new SearchFilter("volunteer.memberCode", SearchFilter.Operator.EQ, memberCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByMember(Long volunteerId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String, Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.id", new SearchFilter("volunteer.id", SearchFilter.Operator.EQ, volunteerId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByActivity(String activityCode, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String, Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("activity.activityCode", new SearchFilter("activity.activityCode", SearchFilter.Operator.EQ, activityCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByActivity(Long activityId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String, Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("activity.id", new SearchFilter("activity.id", SearchFilter.Operator.EQ, activityId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public List<ActivitySignRecord> queryByMemberAndActivity(String memberCode, String activityCode, int pageNumber) throws ServiceRuntimeException
    {
        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.memberCode", new SearchFilter("volunteer.memberCode", SearchFilter.Operator.EQ, memberCode));
        filters.put("activity.activityCode", new SearchFilter("activity.activityCode", SearchFilter.Operator.EQ, activityCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec);
    }

    @Override
    public List<ActivitySignRecord> queryByMemberAndActivity(Long volunteerId, Long activityId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String, Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.id", new SearchFilter("volunteer.id", SearchFilter.Operator.EQ, volunteerId));
        filters.put("activity.id", new SearchFilter("activity.id", SearchFilter.Operator.EQ, activityId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec);
    }

    @Override
    public String findFirstRecord(Long volunteerId, Long activityId) throws ServiceRuntimeException
    {
        return this.activitySignRecordDao.findFirstRecord(volunteerId, activityId);
    }

    @Override
    public String findLastRecord(Long volunteerId, Long activityId) throws ServiceRuntimeException
    {
        return this.activitySignRecordDao.findLastRecord(volunteerId, activityId);
    }
}
